package jus.poc.prodcons.v4;

import java.util.Date;
import jus.poc.prodcons.*;

/**
 * ProdCons gère les échanges à partir des buffers
 *
 * @author Nunes Thomas <nds.thomas@gmail.com>
 * @author Feng Xu <fengxu1989@gmail.com>
 */
public class ProdCons implements Tampon {

    protected int nbBuffer;
    protected Message buffers[];
    protected int enAttente;
    protected int indice;
    protected Semaphore mutex = new Semaphore(1);
    protected Semaphore attente = new Semaphore(0);
    protected Semaphore ecrit;
    protected int tickets = 0;
    protected int on_tickets = 0;

    public ProdCons(int nbBuffer) {
        this.nbBuffer = nbBuffer;
        buffers = new Message[nbBuffer];
        enAttente = 0;
        indice = 0;
        ecrit = new Semaphore(nbBuffer);
    }

    @Override
    public int enAttente() {
        return enAttente;
    }

    @Override
    public Message get(_Consommateur arg0) throws Exception,
            InterruptedException {
        MessageX m;
        attente.P();
        mutex.P();

        m = ((MessageX) buffers[mod((indice - enAttente), nbBuffer)]);
        ((MessageX) buffers[mod((indice - enAttente), nbBuffer)]).exemplaireLu();
        m.addRecu(arg0.toString(), new Date());
        if (m.getExemplaires() == 0) {
            enAttente--;
            ecrit.V();
            System.out.println(m.id() + " est totalement retire");
            m.suspensionRelease();

        } else {
            attente.V();
        }
        mutex.V();
        m.suspensionAcquire();
        synchronized (this) {
            while (on_tickets < m.getTicket()) {
                wait();
            }
        }

        return m;
    }

    @Override
    public void put(_Producteur arg0, Message arg1) throws Exception,
            InterruptedException {
        ecrit.P();

        mutex.P();
        ((MessageX) arg1).setDate(new Date());
        System.out.println(((MessageX) arg1).id() + " insere, nombre d'exemplaires : " + ((MessageX) arg1).getExemplaires());
        ((MessageX) arg1).setTicket(tickets++);
        buffers[indice] = arg1;
        indice = (indice + 1) % nbBuffer;
        enAttente++;
        attente.V();


        mutex.V();
        ((MessageX) arg1).suspensionAcquire();

    }

    @Override
    public int taille() {
        return nbBuffer;
    }

    private int mod(int a, int b) {
        int res = a % b;
        if (res < 0 && b > 0) {
            res += b;
        }
        return res;
    }

    public synchronized void LibererConsommation() {
        on_tickets++;
        notifyAll();
    }
}
